#pragma once

#include <Common/Base.hpp>
#include <Common/Math.hpp>
#include <Common/Error.hpp>
#include <Common/DateTime.hpp>
#include <Common/Files.hpp>
#include <Common/FreeList.hpp>
#include <Common/Logger.hpp>
#include <Common/Math.hpp>
#include <Common/Profiler.hpp>
#include <Common/Stream.hpp>
#include <Common/Threads.hpp>
#include <Common/Tokenizer.hpp>
#include <Common/TokDoc.hpp>
#include <Common/ZlibUtils.hpp>

using namespace common;

#include <AntTweakBar.h>

#include <d3dx9.h>
#include <dxerr.h>

#include <NxPhysics.h>

#include <windows.h>

#include <string>
#include <vector>
#include <set>
#include <map>
#include <algorithm>

#include <cassert>
#include <cstdlib>


const uint LOG_ERROR   = 0x00010000;
const uint LOG_WARNING = 0x00020000;
const uint LOG_DEBUG   = 0x00040000;

const uint LOG_APP      = 0x00000002;
const uint LOG_RESMNGR  = 0x00000004;
const uint LOG_RENDERER = 0x00000008;
const uint LOG_PHYSICS  = 0x00000010;

extern const char * const PROGRAM_TITLE;

void LogError(uint Mask, const common::Error &e);

struct EnvelopeADSR
{
	GameTime AttackEndX, DecayEndX, SustainEndX, ReleaseEndX;
	float AmplitudeY, SustainY;

	EnvelopeADSR() { }
	EnvelopeADSR(const GameTime &AttackEndX, const GameTime &DecayEndX, const GameTime &SustainEndX, const GameTime &ReleaseEndX, float AmplitudeY, float SustainY)
	: AttackEndX(AttackEndX), DecayEndX(DecayEndX), SustainEndX(SustainEndX), ReleaseEndX(ReleaseEndX), AmplitudeY(AmplitudeY), SustainY(SustainY)
	{
	}

	float Calc(const GameTime &x)
	{
		if (x < GameTime::ZERO || x >= ReleaseEndX) return 0.f;
		else if (x < AttackEndX) return x.ToSeconds_f() * AmplitudeY / AttackEndX.ToSeconds_f();
		else if (x < DecayEndX) return common::Lerp(AmplitudeY, SustainY, (x - AttackEndX).ToSeconds_f() / (DecayEndX - AttackEndX).ToSeconds_f());
		else if (x < SustainEndX) return SustainY;
		else return (- x + ReleaseEndX).ToSeconds_f() * SustainY / (ReleaseEndX - SustainEndX).ToSeconds_f();
	}

	bool Finished(const GameTime &x) { return x >= ReleaseEndX; }
};

void RedirectStandardIo();
